﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;

namespace Communicate
{
    /// <summary>
    /// 用于创建接口实例的类。
    /// </summary>
    public class Transmit
    {
        /// <summary>
        /// 逻辑名。
        /// </summary>
        private string _LogicName;
        /// <summary>
        /// 方法返回类型。
        /// </summary>
        //private Dictionary<string, Type> _MethodsReturnType;
        /// <summary>
        /// 模板。
        /// </summary>
        private static ModuleBuilder _ModuleBuilder;
        /// <summary>
        /// 构造类。
        /// </summary>
        static Transmit()
        {
            AppDomain myDomain = Thread.GetDomain();
            AssemblyName myAsmName = new AssemblyName();
            myAsmName.Name = "Transmit";
            AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess.RunAndSave);
            _ModuleBuilder = myAsmBuilder.DefineDynamicModule("TransmitModule", "Transmit.dll");
        }
        /// <summary>
        /// 创建虚拟类。
        /// </summary>
        /// <param name="targetType">被继续的类。</param>
        /// <returns>返回类。</returns>
        internal static object CreateInterface(Type targetType)
        {
            Type createType = _ModuleBuilder.GetType(targetType.FullName);
            if (createType != null)
            {
                return _ModuleBuilder.Assembly.CreateInstance(targetType.Name);
            }
            TypeBuilder typeBuilder = _ModuleBuilder.DefineType(targetType.FullName, TypeAttributes.Class | TypeAttributes.Public, typeof(Transmit), new Type[] { targetType });
            //以下将为新类型声明方法：新类型应该override基类型的所以virtual方法。
            //得到基类型的所有方法。
            List<MemberInfo> targetMethods = new List<MemberInfo>();
            //该类的方法。
            targetMethods.AddRange(targetType.GetMethods());
            foreach (Type type in targetType.GetInterfaces())
            {
                targetMethods.AddRange(type.GetMethods());
            }
            //记录每个方法的返回类型。
            //Dictionary<string, Type> _MethodReturnTypeList = new Dictionary<string, Type>();
            //遍历各个方法，对于Virtual的方法，获取其签名，作为新类型的方法。
            foreach (MethodInfo targetMethod in targetMethods)
            {
                //只挑出virtual的方法。
                if (targetMethod.IsVirtual)
                {
                    //得到方法的各个参数的类型。
                    ParameterInfo[] paramInfo = targetMethod.GetParameters();
                    Type[] paramType = new Type[paramInfo.Length];
                    for (int i = 0; i < paramInfo.Length; i++)
                        paramType[i] = paramInfo[i].ParameterType;
                    //传入方法签名，得到方法生成器。
                    MethodBuilder methodBuilder = typeBuilder.DefineMethod(targetMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual, targetMethod.ReturnType, paramType);
                    //由于要生成的是具体类，所以方法的实现是必不可少的。而方法的实现是通过Emit IL代码来产生的。
                    //得到IL生成器
                    ILGenerator ilGen = methodBuilder.GetILGenerator();
                    /*
                     * 实现 return PostToService(methodName, object[] args);
                     */
                    //object[] local = null;
                    LocalBuilder local = ilGen.DeclareLocal(typeof(Object[]));
                    //local = new object[argTypes.length];
                    ilGen.Emit(OpCodes.Ldc_I4, paramType.Length);
                    ilGen.Emit(OpCodes.Newarr, typeof(Object));
                    ilGen.Emit(OpCodes.Stloc, local);
                    for (int j = 0; j < paramType.Length; j++)
                    {
                        //local[j] = arg[j]
                        ilGen.Emit(OpCodes.Ldloc, local);
                        ilGen.Emit(OpCodes.Ldc_I4, j);
                        ilGen.Emit(OpCodes.Ldarg, j + 1);
                        ilGen.Emit(OpCodes.Box, paramType[j]);
                        ilGen.Emit(OpCodes.Stelem_Ref);
                    }
                    ilGen.Emit(OpCodes.Ldarg_0);
                    ilGen.Emit(OpCodes.Ldstr, targetMethod.Name);
                    ilGen.Emit(OpCodes.Ldloc, local);
                    //调用Call方法。
                    ilGen.Emit(OpCodes.Call, typeof(Transmit).GetMethod("PostToService"));
                    if (targetMethod.ReturnType.Equals(typeof(void)))
                    {
                        //如果override方法返回void, 将Call返回的null出栈。
                        ilGen.Emit(OpCodes.Pop);
                    }
                    else
                    {
                        //将返回值是值类型(value type)时拆箱(Unbox)。
                        ilGen.Emit(OpCodes.Unbox_Any, targetMethod.ReturnType);
                        //_MethodReturnTypeList.Add(targetMethod.Name, targetMethod.ReturnType);
                    }
                    ilGen.Emit(OpCodes.Ret);
                }
            }
            Type myType = typeBuilder.CreateType();
            Transmit bcs = (Transmit)Activator.CreateInstance(myType);
            bcs._LogicName = targetType.FullName;
            //bcs._MethodsReturnType = _MethodReturnTypeList;
            return bcs;
        }
        /// <summary>
        /// 交给服务器处理。
        /// </summary>
        /// <param name="methodName">方法名。</param>
        /// <param name="paramList">传入参数。</param>
        /// <returns>返回执行结果。</returns>
        public object PostToService(string methodName, params object[] paramList)
        {
            return Proxy.InvokeMember(_LogicName, methodName, paramList);
        }
    }
}
